﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mighty.Common;
using System.Collections;

namespace Mighty.Brain
{
    public class SangmiBrain : BasicBrain
    {
        /// <summary>
        /// 기본Brain. 모든 Brain의 기본이 되는 Brain이다. 모든 Brain은 이 클래스를 상속받아야만n 한다.
        /// 게임에 관련된 모든 정보를 가지고 있는 gameInfo 속성과 게임으로부터 호출되는 15개의 함수(이벤트)로 구성되어 있다.
        /// 게임으로부터 호출되는 15개의 함수는 다음과 같다.
        /// 
        ///        GameStartEvent,             // (모두) 게임시작
        ///        BettingReadyEvent,          // (모두) 베팅시작, 카드를 이미 나누어 주었다
        ///        BettingTicEvent,            // (개인) 베팅차례
        ///        BettingTalkEvent,           // (모두) 다른사람의 베팅 정보
        ///        BettingCompleteEvent,       // (모두) 베팅완료, 주공이 정해졌다
        ///        ChoiceCardEvent,            // (주공) 카드선택, 13장의 카드중 10장의 카드선택
        ///        LastBettingEvent,           // (주공) 최종베팅정보, 기루다무늬변경가능
        ///        LastBettingTalkEvent,       // (모두) 주공의 최종베팅정보
        ///        ChoiceFriendEvent,          // (주공) 프랜드선택
        ///        ChoiceFriendTalkEvent,      // (모두) 주공의 프랜드 정보
        ///        RoundReadyEvent,            // (모두) 각라운드의시작
        ///        RoundTicEvent,              // (각자) 카드낼차례
        ///        RoundCardThrowEvent,        // (모두) 다른사람의 카드 정보
        ///        RoundCompleteEvent,         // (모두) 각라운드의종료78
        ///        GameEndEvent                // (모두) 게임의 종료
        /// </summary>


        public enum PlayerType { AttackPlayer, FriendPlayer, DependPlayer };
        PlayerType playerType = PlayerType.AttackPlayer;

        private void UpdateMyInfo()
        {
            if (gameInfo.friend.howToSelect == FriendPlayer.HowToSelect.card)
            {
                for (int i = 0; i < 10; i++)
                {
                    if (gameInfo.myCards[i] == gameInfo.friend.cardCondition)
                    {
                        playerType = PlayerType.FriendPlayer;
                        break;
                    }
                }
            }
            else if (gameInfo.friend.howToSelect == FriendPlayer.HowToSelect.firstwin)
            {
                if (gameInfo.roundHistory[0].winner == gameInfo.myInfo.position)
                    playerType = PlayerType.FriendPlayer;
            }
            else if (gameInfo.betting.position != gameInfo.myInfo.position)
            {
                playerType = PlayerType.DependPlayer;
            }
        }



        /// <summary>
        /// 게임시작
        ///  * 매 게임마다 초기화해야할 코드가 있다면 여기에 넣어라
        /// </summary>
        public override void GameStartEvent()
        {
        }

        /// <summary>
        /// 베팅시작
        ///  * 카드를 나누어 주고 호출된다. gameInfo.myCards를 참고
        /// </summary>
        public override void BettingReadyEvent()
        {
        }

        /// <summary>
        /// 베팅차례
        ///  * 지금까지 배팅된 정보(gameInfo.bettingHistory) 또는 마지막 pass가 아닌 베팅정보 gameInfo.betting를 참고하여 베팅을 결정한다
        /// </summary>
        /// <remarks>
        /// [기본행동] 베팅리밋(betting.limit)이 15이하 이면 베팅리밋을 +1하고 노기루다(Giruda.NoGiruda)로 베팅한다
        /// </remarks>
        public override Betting BettingTicEvent()
        {
            Betting betting = new Betting();
            betting.isPass = true;

            //HandedCard[] hArray = gameInfo.myCards.Where(p=>p.number!=0).OrderBy(p => p.number).OrderBy(p=>p.shape).ToArray();

            // 각 무늬의 개수를 센다
            int heart = 0;
            int clover = 0;
            int spade = 0;
            int diamond = 0;
            int joker = 0;
            int mighty = 0;

            for (int i = 0; i < 10; i++)
            {
                HandedCard card = gameInfo.myCards[i];
                if (card.shape == Shape.Clover) clover++;
                else if (card.shape == Shape.Heart) heart++;
                else if (card.shape == Shape.Spade)
                { spade++; if (card.number == 14)mighty++; }
                else if (card.shape == Shape.Diamond) diamond++;
                else joker++;
            }

            // 가장 많은 무늬를 찾아 낸다
            Giruda selectedShape = Giruda.Heart;
            int selectedCount = heart;

            if (clover > selectedCount)
            {
                selectedShape = Giruda.Clover;
                selectedCount = clover;
            }
            if (spade > selectedCount)
            {
                selectedShape = Giruda.Spade;
                selectedCount = spade;
            }
            if (diamond > selectedCount)
            {
                selectedShape = Giruda.Diamond;
                selectedCount = diamond;
            }

            if (gameInfo.betting.limit > 0)
            {

                if (gameInfo.betting.limit < 15)
                {
                    betting.giruda = selectedShape;
                    betting.isPass = false;
                    betting.limit = gameInfo.betting.limit + 1;
                }
                else if (15 <= gameInfo.betting.limit && selectedCount > 5 || (gameInfo.betting.limit < 18 && selectedCount > 3 && (mighty != 0 || joker != 0)))
                {
                    betting.giruda = selectedShape;
                    betting.isPass = false;
                    betting.limit = gameInfo.betting.limit + 1;
                }
                else
                {
                    betting.isPass = true;
                }
            }
            else
            {
                betting.giruda = selectedShape;
                betting.isPass = false;
                betting.limit = 13;
            }
            return betting;
        }

        /// 다른사람의 베팅 정보
        public override void BettingTalkEvent()
        {
        }

        /// 베팅완료, 주공이 정해졌다. 베팅이 끝났을 경우 처리할 코드가 있다면 여기에 하라.
        public override void BettingCompleteEvent()
        {
        }

        /// (주공)카드선택, 13장의 카드중 10장의 카드선택. 버릴3장의 카드에 cmdRemove=true로 설정해주어야 한다
        /// 만약 정확히 3장의 카드가 선택되지 않았을 경우에는 새로추가된 3장의 카드가 그대로 버려진다.
        /// ChoiceCardEvent 가 호출된 후에는 선택된 10장의 카드는 myCards[0]부터 차례대로 배치되고 버려진 3장의 카드는
        /// myCards[10]에서부터 배치되어 나중에 어떤 카드가 버려졌는지 알수 있게 해준다
        public override HandedCard[] ChoiceCardEvent()
        {

            int[] cardScore = new int[13] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

            // 기루다 & 특수카드
            for (int i = 0; i < 13; i++)
            {
                HandedCard h = gameInfo.myCards[i];

                // 기루다
                if ((int)h.shape == (int)gameInfo.betting.giruda) cardScore[i] = 10;

                // 특수카드
                if (h.shape == Shape.Joker) cardScore[i] = 10;
                if (h.IsSame(gameInfo.mighty)) cardScore[i] = 10;

                //에이스
                if (h.number == 14) cardScore[i] = 10;
            }

            for (int i = 0; i < 13; i++)
            {
                if (cardScore[i] == 0 && gameInfo.myCards[i].number > 9)
                    cardScore[i] -= 2;

            }

            int[] cardIndex = new int[13] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
            Array.Sort(cardScore, cardIndex);

            // HandedCard[] hArray = gameInfo.myCards.OrderBy(p => p.number).OrderBy(p => p.shape).ToArray();

            for (int i = 0; i < 3; i++)
            {
                int idx = cardIndex[i];
                gameInfo.myCards[idx].cmdRemove = true;
            }
            for (int i = 3; i < 13; i++)
            {
                int idx = cardIndex[i];
                gameInfo.myCards[idx].cmdRemove = false;
            }


            return gameInfo.myCards;
        }

        /// <summary>
        /// 최종베팅정보, 기루다무늬변경가능. 기루다를 변경할 경우 최소+2된 limit정보를 리턴해야 한다
        /// </summary>
        /// <remarks>
        /// [기본행동] 아무런 변경도 하지 않는다
        /// </remarks>
        public override Betting LastBettingEvent()
        {
            return gameInfo.betting;
        }

        /// <summary>
        /// 주공의 최종베팅정보
        /// </summary>
        public override void LastBettingTalkEvent()
        {
        }

        /// <summary>
        /// (주공)프랜드선택. 프랜드를 선택하는 방법은 노프랜드(FriendPlayer.HowToSelect.nofriend),
        /// 초구프랜드(FriendPlayer.HowToSelect.firstwin),카드프랜드(FriendPlayer.HowToSelect.card)가 있다.
        /// </summary>
        /// <remarks>
        /// [기본행동] 초구프랜드를 선택한다
        /// </remarks>
        public override FriendPlayer ChoiceFriendEvent()
        {
            int mighty = 0;
            int joker = 0;
            int diamondace = 0;
            for (int i = 0; i < 10; i++)
            {
                if (gameInfo.myCards[i].IsSame(gameInfo.mighty) == true)
                    mighty = 1;
                if (gameInfo.myCards[i].shape == Shape.Joker)
                    joker = 1;
                if (gameInfo.myCards[i].shape == Shape.Diamond && gameInfo.myCards[i].number == 14)
                    diamondace = 1;

            }

            if (mighty == 0)
            {
                gameInfo.friend.howToSelect = FriendPlayer.HowToSelect.card;
                gameInfo.friend.cardCondition = gameInfo.mighty;
            }
            else if (joker == 0)
            {
                gameInfo.friend.howToSelect = FriendPlayer.HowToSelect.card;
                gameInfo.friend.cardCondition = new Card(Shape.Joker, 0);
            }
            else if (diamondace == 0)
            {
                gameInfo.friend.howToSelect = FriendPlayer.HowToSelect.card;
                gameInfo.friend.cardCondition = new Card(Shape.Diamond, 14);
            }
            else
                gameInfo.friend.howToSelect = FriendPlayer.HowToSelect.firstwin;

            return gameInfo.friend;
        }

        /// <summary>
        /// 주공의 프랜드 정보
        /// </summary>
        public override void ChoiceFriendTalkEvent()
        {

        }

        /// <summary>
        /// 각라운드의시작
        ///  * 매라운드마다 초기화할 코드가 있다면 이부분에 들어가게 된다
        /// </summary>
        public override void RoundReadyEvent()
        {

        }


        /// <summary>
        /// 카드낼차례
        ///  * 각 사용자의 턴에 한번씩 호출되며 낼 카드를 결과값으로 리턴해야 한다. 
        ///  * 사용가능한 카드에는 myCards[i].isPossible 속성이 true로 설정되어 있다. 
        ///  * 만약 사용불가능한 카드를 낼 경우에 시스템은 카드배열에서 제일 처음 만나는 사용가능한 카드를 골라서 사용한다
        /// </summary>
        /// <remarks>
        /// [기본행동] 가능한 카드중에서 랜덤하게 하나의 카드를 선택한다
        /// </remarks>
        public override HandedCard RoundTicEvent()
        {
            UpdateMyInfo();

            List<HandedCard> possibleCards = new List<HandedCard>();
            foreach (HandedCard card in gameInfo.myCards)
            {
                if (card.isPossible)
                    possibleCards.Add(card);
            }

            //기본행동 : 낼 수 있는 카드중 가장 높은 카드


            /* 이전 사용자들의 playertype(주공,프렌드,수비)을 호출하는 방법을 모르겠어서 보류 ㅠㅠ
             *          int best_player=0;
                        int bestcard_number=0;
                        int bestcard_shape=0;

                        for(int i=0;i<5;i++)
                        {
                            if(gameInfo.round.cardStack[i].number>gameInfo.round.cardStack[i-1].number &&!(gameInfo.round.cardStack[i-1].shape.ToString()==gameInfo.betting.giruda.ToString()&&gameInfo.round.cardStack[i].shape.ToString()!=gameInfo.betting.giruda.ToString())||!((gameInfo.round.cardStack[i-1].shape==gameInfo.round.cardStack[0].shape)&&(gameInfo.round.cardStack[i].shape.ToString()!=gameInfo.round.cardStack[0].shape.ToString())&&(gameInfo.round.cardStack[i].shape.ToString()!=gameInfo.betting.giruda.ToString())))
                            {//마이티나 조커일때도 추가해야함
                                 best_player=i;
                                 bestcard_shape=(int)gameInfo.round.cardStack[i].shape;
                                 bestcard_number=(int)gameInfo.round.cardStack[i].number;

                            }   

                        }
            */
            int Max = 0;
            int Maxcard_locate = 0;
            for (int l = 0; l < possibleCards.Count; l++)
            {
                HandedCard card = possibleCards[l];

                if (Max <= card.number)
                {
                    Max = card.number;
                    Maxcard_locate = l;
                }
            }
            //playertype별 실행은 잠시 보류
            /*            
             *             int k = 0;

                        if (playerType == PlayerType.AttackPlayer)
                        {
               
                            if(true)
                            {

                            }

                            else
                            {
                                Random r = new Random();
                                k = r.Next(possibleCards.Count);

                            }
                
            /*          if(gameInfo.players[best_player].position=="Dependplayer")
                        {
                            //이전에 낸 카드중 FriendPlayer가 가장 높다면 10이상의 카드 - 아니고 내가 그것보다 높은 카드나 기루다가 없다면 가장 낮은 카드를 냄.
                            //이전의 카드가 없다면 내가 낼 수 있는 카드중 가장 높은 카드.


                              for(int locate=0;locate<5;locate++)
                                for (int i = 0; i < possibleCards.Count; i++)
                                {
                                }

                        }
                        else if (playerType == PlayerType.FriendPlayer)
                        {
                            //이전 카드중 주공의 카드가 가장 높다면 10 이상의 카드를 냄. - 아니고 이전 카드보다 높은 카드가 없다면 그냥 가장 낮은 카드를 냄
                
                        }
                        else if(playerType == PlayerType.DependPlayer)
                        {
                            //주공의 카드보다 높은 카드가 있다면 냄
                            //내가 선이라면 가장 높은 카드


                        }
            */

            return possibleCards[Maxcard_locate];
        }

        /// <summary>
        /// 다른사람의 카드 정보
        /// </summary>
        public override void RoundCardThrowEvent()
        {
        }

        /// <summary>
        /// 각라운드의종료, 각 라운드가 종료되면 호출된다. 각 라운드의 승자는 gameinfo의 winner를 참조한다
        /// </summary>
        public override void RoundCompleteEvent()
        {

        }

        /// <summary>
        /// 게임의 종료, 게임이 종료되었을때 실행될 코드는 여기에 추가한다.
        /// </summary>
        public override void GameEndEvent()
        {

        }

    }

}
